import wx
from derbyos import NSOde
from derbyos import NSObject

# need to use wx events to move updates from stopwatch to main event loop        
typeEVT_DidChangeValue = wx.NewEventType()
EVT_DidChangeValue = wx.PyEventBinder(typeEVT_DidChangeValue, 1)


class DidChangeValueEvent(wx.PyCommandEvent):
    """Event to signal that a count value is ready"""

    def __init__(self, etype, eid, args, kws, callback):
        """Creates the event object"""
        wx.PyCommandEvent.__init__(self, etype, eid)
        self._args = args
        self._kws = kws
        self._callback = callback

    def invoke(self):
        self._callback(*self._args, **self._kws)


# instead of: object.addObserver(routine,attr)
# use: object.addObserver(UpdateOnMainThread(frame,routine),attr)

class UpdateOnMainThread(object):
    def __init__(self, frame, callback):
        self._callback = callback
        self._frame = frame
        frame.Bind(EVT_DidChangeValue, self.OnUpdate)  # add this to be run on main event

    def OnUpdate(self, event):
        event.invoke()

    def __call__(self, *param, **kws):  # this gets called in the bg thread
        evt = DidChangeValueEvent(typeEVT_DidChangeValue, -1, param, kws, self._callback)
        wx.PostEvent(self._frame, evt)  # and run in main thread


class UpdateLabelOnMainThread(UpdateOnMainThread):
    def __init__(self, frame, label, fmt=None):
        def SetLabelText(obj, name, value):
            if self.fmt:
                value = self.fmt(value)
            else:
                value = str(value)
            self.label.SetLabelText(value)

        super(UpdateLabelOnMainThread, self).__init__(frame, SetLabelText)
        self.fmt = fmt
        self.label = label


# simple "test a frame" rig
def testWX(name, frameCls, optionsParser=None):
    import zmq
    import derbyos.Defaults

    if optionsParser is None:  # otherwise the caller did something special
        optionsParser = derbyos.Defaults.OptionsParser()
    (options, args) = optionsParser.parse_args()
    derbyos.Defaults.ConfigureOptions(options)

    ctx = zmq.Context()
    n = NSOde(ctx)
    n.pollInBackground()
    app = wx.App()
    frame = frameCls(n)
    frame.Show()

    menubar = wx.MenuBar()
    fileMenu = wx.Menu()
    fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quit ' + name)
    menubar.Append(fileMenu, '&File')
    frame.SetMenuBar(menubar)

    def close(event):
        frame.Close()

    frame.Bind(wx.EVT_MENU, close, fitem)

    app.MainLoop()


class Stopwatcher(object):
    # throttle stopwatch to only fire an updated when it changes
    # Will both call the NSOde to update the timer, but will also then
    # call back to some other routine (this is all done on the main thread)
    def __init__(self, stopwatch, name, nsode, updater):
        self.nsode = nsode
        self.curValue = -1
        self.isRunning = False
        self.stopwatch = stopwatch
        self.name = name
        self.updater = updater

        def timeChanged(stopwatch, attr, value):
            changed = False
            if int(self.stopwatch.elapsedTime) != self.curValue:
                self.curValue = int(self.stopwatch.elapsedTime)
                self.nsode.UpdateTimer(self.name, self.curValue)
                changed = True
            if self.isRunning != self.stopwatch.IsRunning():
                self.isRunning = self.stopwatch.IsRunning()
                if self.isRunning:
                    self.nsode.StartTimer(self.name)
                else:
                    self.nsode.StopTimer(self.name)
                changed = True
            if changed:
                self.updater(self.stopwatch)

        stopwatch.addObserver(timeChanged, 'elapsedTime')


class TeamRoster(NSObject.NSObject):
    def __init__(self, nsode, frame):
        super(TeamRoster, self).__init__()
        self.nsode = nsode
        self.team = None
        if not self.team:
            self.team = self.nsode.derbyXML.teams()[0]
        self.listbox = wx.ListBox(frame, -1, size=(100, 300))

        self.sizer = wx.FlexGridSizer(wx.VERTICAL, 1, 2)

        self.noSkater = wx.Button(frame, -1, "None")
        frame.Bind(wx.EVT_BUTTON, self.OnNone, self.noSkater)
        frame.Bind(wx.EVT_LISTBOX, self.OnSelectSkater, self.listbox)
        self.sizer.Add(self.noSkater, 0, wx.EXPAND)
        self.sizer.Add(self.listbox, 1, wx.EXPAND)
        self.PopulateTeam()
        self._currentSkater = None

    def OnNone(self, event):
        self.listbox.DeselectAll()
        self.currentSkater = None

    def OnSelectSkater(self, event):
        sel = self.listbox.GetSelection()
        if sel == wx.NOT_FOUND:
            self.currentSkater = None
        else:
            self.currentSkater = self.team.skaters[sel]
        print "new selection", sel, self.currentSkater, self.team.skaters[sel]

    def PopulateTeam(self):
        self.listbox.Clear()
        for skater in self.team.skaters:
            self.listbox.Append(skater.number)

    @property
    def currentSkater(self):
        return self._currentSkater

    @currentSkater.setter
    def currentSkater(self, value):
        print "changing current skater to", value
        self._currentSkater = value
        if value is None:
            self.listbox.DeselectAll()
        else:
            self.listbox.Select(self.team.skaters().index(value))
        self.didChangeValue('currentSkater', value)
    
    